#include "UsbAVStream.h"
#include "log.h"
#include <unistd.h>

extern "C" unsigned long long vdo_get_time();

namespace Media{

mutex UsbAVStream::m_instanceLock;
UsbAVStream *UsbAVStream::sm_usbAVStream = nullptr;

UsbAVStream *UsbAVStream::instance(){
	lock_guard<mutex> instance_lock(m_instanceLock);
	if(sm_usbAVStream == nullptr){
		sm_usbAVStream = new UsbAVStream();
	}
	return sm_usbAVStream;
}

bool UsbAVStream::addDevice(string usbport, int ability, int devicenum){
	lock_guard<mutex> addevice(m_deviceLock);
	LOG_PrintWarn("---------------------------------------ability start  %lld\n", vdo_get_time());
	map<string, UsbStream *>::iterator deviceit;
	map<string, int>::iterator abilityit;
	//第一个能力创建的时候，创建对象
	abilityit = m_usbAbility.find(usbport);
	if(abilityit == m_usbAbility.end()){
		m_usbAbility[usbport] = 0;
		abilityit = m_usbAbility.find(usbport);
	}
	//查找能力map如果对象（如果不存在就创建）已经具备了这个能力就不需要创建了
	LOG_PrintInfo("abilityit -> second:%d -----> ability:%d  -----> &:%d\n", abilityit -> second, ability, abilityit -> second & ability);
	if((abilityit -> second & ability) != 0){
		LOG_PrintError("the device:%s ability:%d exist cannot add again\n", usbport.c_str(), ability);
		return false;
	}
	//查找设备的map如果不存在对象就创建对象，如果存在对象直接拿来用
	deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		//LOG_PrintWarn("m_deviceMap -------------------------------------------------- add\n");
		m_deviceMap[usbport] = new UsbStream();
		deviceit = m_deviceMap.find(usbport);

		m_cbMask[usbport] = true;

		//添加创建的时间，为了保证所有的能力全部加入成功之后才获取
		m_usbTime[usbport] = vdo_get_time();
		if(usbport == USB_IN_1)
		{
			m_hotplugTimer1.reset(new Fdt::Timer(1000, ([this](){return this->notiftyHotplugIn1();}), nullptr));
		}
		else if(usbport == USB_IN_2)
		{
			m_hotplugTimer2.reset(new Fdt::Timer(1000, ([this](){return this->notiftyHotplugIn2();}), nullptr));
		}
	}
	//为设备添加能力，先调用设备对象的方法创建对象，在创建成功之后添加设备能力
	if(!(deviceit -> second -> addStreamObject(ability, devicenum))){
		LOG_PrintError("faild to device:%s ability:%d\n", usbport.c_str(), ability);
		return false;
	}
	if(!(addAbility(usbport, ability))){
		LOG_PrintError("faild to device:%s ability:%d\n", usbport.c_str(), ability);
		return false;
	}

	if(ability == UVCIN){
		m_videoDeviceNumberMap[usbport] = devicenum;
	}


	for(abilityit = m_usbAbility.begin(); abilityit != m_usbAbility.end(); abilityit++){
		LOG_PrintInfo("%s ----> %d\n", (abilityit -> first).c_str(),  abilityit -> second);
	}
	LOG_PrintWarn("ability end\n");
	return true;
}

bool UsbAVStream::removeDevice(string usbport, int ability){
	lock_guard<mutex> removedevice(m_deviceLock);
	map<string, UsbStream *>::iterator deviceit;
	map<string, int>::iterator abilityit;
	int abilitys[3] = {UVCIN, UACOUT, UACIN};
	//查找设备能力的map如果本来就不存在能力就直接不处理
	abilityit = m_usbAbility.find(usbport);
	LOG_PrintInfo("abilityit -> second:%d -----> ability:%d  -----> &:%d\n", abilityit -> second, ability, abilityit -> second & ability);
	if(abilityit == m_usbAbility.end() || (((abilityit -> second) & ability) == 0)){
		LOG_PrintError("faild to device:%s ability:%d the device not exist\n", usbport.c_str(), ability);
		return false;
	}

    if(usbport == USB_IN_1)
    {
	    m_hotplugTimer1.reset();
	}
	else if(usbport == USB_IN_2)
	{
        m_hotplugTimer2.reset();    
	}

	//删除设备map对应设备的能力
	deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		LOG_PrintError("faild to device:%s ability:%d the device not exist\n", usbport.c_str(), ability);
		return false;
	}

	for(int i = 0; i < 3; i++){
		if((abilityit->second) & abilitys[i] == 0){
			continue;
		}
	
		if(!(deviceit -> second -> removeStreamObject(abilitys[i]))){
			LOG_PrintError("faild to device:%s ability:%d\n", usbport.c_str(), abilitys[i]);
		}
		//消除能力
		if(!(removeAbility(usbport, abilitys[i]))){
			LOG_PrintError("faild to device:%s ability:%d\n", usbport.c_str(), abilitys[i]);
		}
		if(abilitys[i] == UVCIN){
			m_videoDeviceNumberMap.erase(usbport);
		}
	}

	if(m_cbMask.find(usbport) != m_cbMask.end()){
		//第一次的removeDevice调用注册的回调函数
		if(m_cbMap.find(usbport) != m_cbMap.end()){
			(m_cbMap.find(usbport) -> second)(usbport, false);
		}
		m_cbMask.erase(usbport);
	}

	//如果现在对象已经没有能力了就直接删除对象，调用对象的delete方法并且将对象从map中删除
	if(abilityit -> second == 0){
		//LOG_PrintWarn("remove -------------------------------------------------------m_cbMap\n");	
		delete(deviceit -> second);
		deviceit -> second = nullptr;
		m_deviceMap.erase(usbport);
		m_usbAbility.erase(usbport);
		m_usbTime.erase(usbport);
	}

	
	
	LOG_PrintWarn("ability start\n");
	for(abilityit = m_usbAbility.begin(); abilityit != m_usbAbility.end(); abilityit++){
		LOG_PrintInfo("%s ----> %d\n", (abilityit -> first).c_str(),  abilityit -> second);
	}
	LOG_PrintWarn("ability end\n");
	return true;
}

bool UsbAVStream::getAblilityMap(map<string, int> &abilitys){
	//过滤未全部初始化的map
	abilitys.clear();
	map<string, int>::iterator abilityit;
	for(abilityit = m_usbAbility.begin(); abilityit != m_usbAbility.end(); abilityit++){
		if(isVisibility(abilityit -> first)){
			abilitys[abilityit -> first] = abilityit -> second;
		}
	}
	return true;
}

bool UsbAVStream::getAbility(string key, int &ability){
	map<string, int>::iterator abilityit;
	//查看map中是否存在不存在就为0
	abilityit = m_usbAbility.find(key);
	if(abilityit == m_usbAbility.end() || !isVisibility(key)){
		ability = 0;
	}else{
		ability = abilityit -> second;
	}
	return true;
}

bool UsbAVStream::getDeviceMap(map<string, UsbStream *> &devices){
	//过滤未全部初始化的map
	devices.clear();
	map<string, UsbStream*>::iterator devit;
	for(devit = m_deviceMap.begin(); devit != m_deviceMap.end(); devit++){
		if(isVisibility(devit -> first)){
			devices[devit -> first] = devit -> second;
		}
	}
	return true;
}

bool UsbAVStream::getDevice(string key, UsbStream **device){
	map<string, UsbStream *>::iterator deviceit;
	//查找对象是否存在map中不存在就为空
	deviceit = m_deviceMap.find(key);
	if(deviceit == m_deviceMap.end() || !isVisibility(deviceit -> first)){
		*device = nullptr;
	}else{
		*device = deviceit -> second;
	}
	return true;
}

bool UsbAVStream::addAbility(string usbport, int ability){
	map<string, int>::iterator abilityit = m_usbAbility.find(usbport);
	if(abilityit == m_usbAbility.end() || ((abilityit -> second) & ability) != 0){
		LOG_PrintError("add ability faild usbport:%s  ability:%d\n", usbport.c_str(), ability);
		return false;
	}
	int old_ability = abilityit -> second;
	int new_ability = (old_ability | ability);
	abilityit -> second = new_ability;
	return true;
}

bool UsbAVStream::removeAbility(string usbport, int ability){
	map<string, int>::iterator abilityit = m_usbAbility.find(usbport);
	if(abilityit == m_usbAbility.end() || ((abilityit -> second) & ability) == 0){
		LOG_PrintError("add ability faild usbport:%s  ability:%d\n", usbport.c_str(), ability);
		return false;
	}
	int old_ability = abilityit -> second;
	int new_ability = (old_ability & (~ability));
	abilityit -> second = new_ability;
	return true;
}

bool UsbAVStream::addHotplugCb(string usbport, callback_hotplug cb){
	m_cbMap[usbport] = cb;
	return true;
}

bool UsbAVStream::removeHotplugCb(string usbport){
	m_cbMap.erase(usbport);
	return true;
}

bool UsbAVStream::isVisibility(string usbport){
	map<string, long long>::iterator timeit = m_usbTime.find(usbport);
	if(timeit == m_usbTime.end()){
		return false;
	}
	if(vdo_get_time() - (timeit -> second) <= 500){
		return false;
	}
	return true;
}

bool UsbAVStream::getSupportParams(string usbport, int ability, Json::Value &params){
	lock_guard<mutex> supportParamDevice(m_deviceLock);
	map<string, UsbStream*>::iterator deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		LOG_PrintError("the device is uncontect %s\n", usbport.c_str());
		return false;
	}
	return deviceit -> second -> getSupportParams(ability, params);
}



bool UsbAVStream::setParams(string usbport, int ability, const Json::Value params){
	lock_guard<mutex> paramsDevice(m_deviceLock);
	map<string, UsbStream*>::iterator deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		LOG_PrintError("the device is uncontect %s\n", usbport.c_str());
		return false;
	}
	return deviceit -> second -> setParams(ability, params);
}

bool UsbAVStream::startStream(string usbport, int ability, callback_t cb){
	lock_guard<mutex> startstream(m_deviceLock);
	map<string, UsbStream*>::iterator deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		LOG_PrintError("the device is uncontect %s\n", usbport.c_str());
		return false;
	}
	return deviceit -> second -> startStream(ability, cb);
}

bool UsbAVStream::stopStream(string usbport, int ability){
	lock_guard<mutex> stopStream(m_deviceLock);
	map<string, UsbStream*>::iterator deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		LOG_PrintError("the device is uncontect %s\n", usbport.c_str());
		return false;
	}
	return deviceit -> second -> stopStream(ability);
}

bool UsbAVStream::writeStream(string usbport, int ability, void *buffer, int length){
	lock_guard<mutex> writeStream(m_deviceLock);
	map<string, UsbStream*>::iterator deviceit = m_deviceMap.find(usbport);
	if(deviceit == m_deviceMap.end()){
		LOG_PrintError("the device is uncontect %s\n", usbport.c_str());
		return false;
	}
	return deviceit -> second -> writeStream(ability, buffer, length);
}

bool UsbAVStream::getDeviceName(string port, string &devName){
	//判断当前要查询的USB设备是否插入
	int ability;
	getAbility(port, ability);
	//获取能力
	if(ability == 0){
		return false;
	}
	//如果是视频设备获取视频的信息,获取,结束返回
	if(ability & UVCIN){
		//打开文件读取信息
		char line[128] = {0};
		char videoInfoPath[64] = {0};
		int video_num = 0;
		map<string, int>::iterator numit =  m_videoDeviceNumberMap.find(port);
		if(numit == m_videoDeviceNumberMap.end()){
			LOG_PrintError("Cannot get Video Device Number Info\n");
		}else{
			video_num = m_videoDeviceNumberMap[port];
			sprintf(videoInfoPath, "/sys/class/video4linux/video%d/name", video_num);
			if(access(videoInfoPath, F_OK)){
				LOG_PrintError("not exist %s.\n", videoInfoPath);
			}
			//信息不为空直接返回
			FILE * fp = fopen(videoInfoPath, "r");
			if(!fp){
				LOG_PrintError("Fail to open %s.\n", videoInfoPath);
				return false;
			}
			//读取命令的返回值
			fgets(line, sizeof(line), fp);
			devName = line;
			//LOG_PrintWarn("video_num:%d   line:%s\n", video_num, line);
			if(!devName.empty()){
				string::size_type end_name = devName.find(":");
				if(end_name != devName.npos){
					devName = devName.substr(0,end_name);
				}
				fclose(fp);
				return true;
			}
			fclose(fp);
		}		
	}
	//如果是音频设备获取音频设备的名称，返回
	if((ability & UACIN) || (ability & UACOUT)){
		//LOG_PrintInfo("get a Audio Device Info ability:%d\n", ability);
		//获取card信息
		set<string> devs;
		set<string> cards;
		set<string>::iterator it;
		//获取当前声卡和设备节点的信息
		if(!UacUtil::getSoundInfo(devs, cards)){
			LOG_PrintError("cannot UacUtil::getSoundInfo\n");
			return false;
		}
		//截取cards中的信息，信息不为空直接返回
		for(it = cards.begin(); it != cards.end(); it++){
			string audioInfo = (*it);
			//LOG_PrintInfo("audioInfo:%s    ------>   port:%s\n", audioInfo.c_str(), port.c_str());
			if(audioInfo.find(port) != audioInfo.npos){
				//截取出有用的信息
				int start = audioInfo.find("[");
				int end   = audioInfo.find("]");
				devName = audioInfo.substr(start + 1, end - start - 1);
				if(!devName.empty()){
					devName.erase(devName.find_last_not_of(" ") + 1);
					return true;
				}else{
					return false;
				}
			}
		}
	}
	//如果都没有获取到直接返回false
	return false;
}

bool UsbAVStream::notiftyHotplugIn1()
{
        //重新插入拉流的回调
	if(m_cbMap.find(USB_IN_1) != m_cbMap.end()){
		(m_cbMap.find(USB_IN_1) -> second)(USB_IN_1, true);
	}

	m_hotplugTimer1.reset();

	return true;
}

bool UsbAVStream::notiftyHotplugIn2()
{
    //重新插入拉流的回调
	if(m_cbMap.find(USB_IN_2) != m_cbMap.end()){
		(m_cbMap.find(USB_IN_2) -> second)(USB_IN_2, true);
	}

	m_hotplugTimer2.reset();

	return true;
}


bool UsbAVStream::getUsbStreamPos(map<string, string>& posInfo, bool& isUpdate)
{
    std::lock_guard<std::mutex> guard(m_posMutex);
     
    map<string, string> curInfo = m_usbStreamPos;
    isUpdate= false;

    string usbPort[2] = {USB_IN_1, USB_IN_2};
    int ability = 0;
    
    for(int i = 0; i < 2; ++i)
    {
        ability = 0;
        getAbility(usbPort[i], ability);

        LOG_PrintInfo("usbPort:%s, ability=%d\n", usbPort[i].c_str(), ability);

        ability = (ability & 0xff);

        switch(ability)
    	{
            case 0x01:
            case 0x03:
            case 0x05:
            { 
                curInfo["video"] = usbPort[i];
                break;
            }
            case 0x06:
            {
                curInfo["audio"] = usbPort[i];
                break;
            }            
            case 0x07:
            { 
                curInfo["video"] = usbPort[i];
                curInfo["audio"] = usbPort[i];
                break;
            }
            default:
                break;
    	}	
    }

    posInfo = curInfo;

    if(curInfo != m_usbStreamPos)
    {
        m_usbStreamPos = curInfo;

        isUpdate = true;
    }

    LOG_PrintWarn("UsbAVStream::getUsbStreamPos isUpdate:%d, videoport=%s, audioport=%s\n", isUpdate, curInfo["video"].c_str(), curInfo["audio"].c_str());

    return true;   
}

bool UsbAVStream::getUsbPlayPos(map<string, string>& posInfo)
{
    std::lock_guard<std::mutex> guard(m_posMutex);

    posInfo = m_usbStreamPos;

    return true;

}

bool UsbAVStream::getUacOutStatus(string &usbPos)
{
    bool iRet = false;
    string usbPort[2] = {USB_IN_1, USB_IN_2};
    int ability = 0;
    string  port;                                                                                                  
    
    for(int i = 0; i < 2; ++i)
    {
        ability = 0;
        getAbility(usbPort[i], ability);

        LOG_PrintInfo("getUacOutStatus usbPos:%s, ability=0x%02x\n", usbPort[i].c_str(), ability);

        if((ability & UACOUT) == UACOUT)
        { 
            port = usbPort[i];
            iRet = true;
        }
    }

    if(iRet)
    {
        usbPos = port;
        LOG_PrintInfo("getUacOutStatus usbPos:%s\n", usbPos.c_str());
    }

    return iRet;

}


}
